home *** CD-ROM | disk | FTP | other *** search
/ MacFormat 1995 May / macformat-024.iso / Shareware City / Developers / kvik / src / compile.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-11-21  |  8.4 KB  |  391 lines  |  [TEXT/MPS ]

  1. /** compile.c
  2.  ** Main compilation routines.
  3.  **
  4.  ** Written by and Copyright 1994 Asher Hoskins.
  5.  **
  6.  ** The author retains copyright on this implementation. Permission for
  7.  ** educational and non-profit use is granted to all. If you're planning to
  8.  ** make money with this or any code derived from it, check with the author
  9.  ** first.
  10.  **/
  11.  
  12. #include <stdio.h>
  13. #include "compile.h"
  14. #include "parse.h"
  15.  
  16. static token_val_t err_get_token(char *, int *, int);
  17. static char *err_trans(int);
  18. static void compile_statement(char *, int *, FILE *, int);
  19. static void show_err(char *, int);
  20. static void needs_token(token_t, char *, int *, int);
  21. static int isrelop(token_t);
  22. static int isexprarg(token_t);
  23. static int isexprop(token_t);
  24. static char *expr_arg(token_val_t);
  25. static void assignment(token_val_t, char *, int *, FILE *, int);
  26.  
  27. /** Output stuff before main code.
  28.  **/
  29.  
  30. void start_compile(FILE *out, int argc, char *argv[])
  31. {
  32.     fputs("/* Compiled by kvik */\n", out);
  33.     fputs("#include \"kvik_obj_header.h\"\n", out);
  34.     if (argc > 2)
  35.         fprintf(out, "#include \"%s\"\n", argv[2]);
  36. }
  37.  
  38. /** Output stuff after main code.
  39.  **/
  40.  
  41. void end_compile(FILE *out)
  42. {
  43.     fputs("#include \"kvik_obj_tail.h\"\n", out);
  44.     fputs("/* end */\n", out);
  45. }
  46.  
  47. /** Compile a line.
  48.  **/
  49.  
  50. void compile_line(char *line, FILE *out, int linenum)
  51. {
  52.     token_val_t t;
  53.     int offset = 0;
  54.  
  55.     compile_statement(line, &offset, out, linenum);
  56.     t = err_get_token(line, &offset, linenum);
  57.     if (t.token != T_NEWLINE) {
  58.         fprintf(stderr, "kvik: Too much in line %d.\n", linenum);
  59.         exit(1);
  60.     }
  61. }
  62.  
  63. /** Compile one statement.
  64.  **/
  65.  
  66. static void compile_statement(char *line, int *offset, FILE *out, int linenum)
  67. {
  68.     token_val_t t, tstore;
  69.     char digit;
  70.  
  71.     t = err_get_token(line, offset, linenum);
  72.     switch (t.token) {
  73.  
  74.     case T_NEWLINE:
  75.         return;
  76.  
  77.     case T_PROGRAM_POINTER_DEF:
  78.         fprintf(out, "case %s:\n", t.val.label);
  79.         return;
  80.  
  81.     case T_PROG_POINTER_STORE_DEF: case T_DATA_POINTER_DEF:
  82.         tstore = t;
  83.         t = err_get_token(line, offset, linenum);
  84.         if (t.token == T_BIGNUM) {
  85.             fprintf(out, "alloc_storage(%s, %d, %d);\n", tstore.val.label,
  86.                 t.val.num, (tstore.token==T_DATA_POINTER_DEF)?0:-3);
  87.             return;
  88.         }
  89.         break;
  90.  
  91.     case T_POINTS_TO:
  92.         t = err_get_token(line, offset, linenum);
  93.         if (t.token == T_PROGRAM_POINTER) {
  94.             fprintf(out, "gd = p[%d]; break;\n", t.val.digit);
  95.             return;
  96.         }
  97.         break;
  98.  
  99.     case T_PROGRAM_POINTER:
  100.         digit = t.val.digit;
  101.         t = err_get_token(line, offset, linenum);
  102.         switch (t.token) {
  103.         case T_POINTS_TO:
  104.             t = err_get_token(line, offset, linenum);
  105.             if (t.token == T_BIGNUM) {
  106.                 fprintf(out, "p[%d] = %d;\n", digit, t.val.num);
  107.                 return;
  108.             }
  109.         case T_ASSIGN:
  110.             t = err_get_token(line, offset, linenum);
  111.             if (t.token == T_DATA_POINTER) {
  112.                 fprintf(out, "p[%d] = read_data(&d[%d]);\n", digit,
  113.                     t.val.digit);
  114.                 return;
  115.             }
  116.         }
  117.         break;
  118.  
  119.     case T_REGISTER: case T_DATA_POINTER: case T_CHANNEL: case T_NUMBER:
  120.     case T_CONSTANT:
  121.         tstore = t;
  122.         t = err_get_token(line, offset, linenum);
  123.         switch (t.token) {
  124.  
  125.         case T_PREVIOUS:
  126.             fprintf(out, "previous(&d[%d]);\n", tstore.val.digit);
  127.             return;
  128.  
  129.         case T_NEXT:
  130.             fprintf(out, "next(&d[%d]);\n", tstore.val.digit);
  131.             return;
  132.  
  133.         case T_POINTS_TO:
  134.             t = err_get_token(line, offset, linenum);
  135.             fprintf(out, "set_dp(&d[%d], %d, ", tstore.val.digit, t.val.num);
  136.             t = err_get_token(line, offset, linenum);
  137.             switch (t.token) {
  138.             case T_NEWLINE:
  139.                 fputs("0);\n", out);
  140.                 return;
  141.             case T_NUMBER:
  142.                 fprintf(out, "%d);\n", t.val.num);
  143.                 return;
  144.             case T_REGISTER:
  145.                 fprintf(out, "r[%d]);\n", t.val.digit);
  146.                 return;
  147.             case T_DATA_POINTER:
  148.                 fprintf(out, "read_data(&d[%d]));\n", digit);
  149.                 return;
  150.             }
  151.             break;
  152.  
  153.         case T_ASSIGN:
  154.             assignment(tstore, line, offset, out, linenum);
  155.             return;
  156.  
  157.         default:
  158.             if (isrelop(t.token)) {
  159.                 fprintf(out, "if (expr(1, %s, %d, ", expr_arg(tstore),
  160.                     t.token);
  161.                 t = err_get_token(line, offset, linenum);
  162.                 if (isexprarg(t.token)) {
  163.                     fprintf(out, "1, %s)) {\n", expr_arg(t));
  164.                     needs_token(T_POINTS_TO, line, offset, linenum);
  165.                     t = err_get_token(line, offset, linenum);
  166.                     if (t.token == T_PROGRAM_POINTER) {
  167.                         fprintf(out, " gd = p[%d]; break;\n}\n", t.val.digit);
  168.                         return;
  169.                     }
  170.                 }
  171.             }
  172.         }
  173.     }
  174.  
  175.     fprintf(stderr, "kvik: Syntax error in line %d:\n", linenum);
  176.     show_err(line, *offset);
  177.     exit(1);
  178. }
  179.  
  180. /** Read a token, exiting if there's an error.
  181.  **/
  182.  
  183. static token_val_t err_get_token(char *line, int *offset, int linenum)
  184. {
  185.     token_val_t ret;
  186.  
  187.     ret = get_token(line, offset);
  188.     if (ret.token != T_ERROR)
  189.         return(ret);
  190.  
  191.     fprintf(stderr, "kvik: %s in line %d:\n", err_trans(ret.val.errnum),
  192.         linenum);
  193.     show_err(line, *offset);
  194.     exit(1);
  195. }
  196.  
  197. /** Translate an error number into text.
  198.  **/
  199.  
  200. static char *err_trans(int errnum)
  201. {
  202.     switch(errnum) {
  203.     case PE_TRUNC:
  204.         return("Line too long");
  205.     case PE_BADNUM:
  206.         return("Bad number");
  207.     case PE_BADTOK:
  208.         return("Unknown token");
  209.     case PE_BADDIGIT:
  210.         return("Bad digit");
  211.     }
  212.  
  213.     return("Error");
  214. }
  215.  
  216. /** Show where in a line an error occurred.
  217.  **/
  218.  
  219. static void show_err(char *line, int offset)
  220. {
  221.     int i;
  222.  
  223.     fputs(line, stderr);
  224.     for (i=0; i<offset; i++)
  225.         putc('-', stderr);
  226.     fputs("^\n", stderr);
  227. }
  228.  
  229. /** Exit if the next token is not 'tok'.
  230.  **/
  231.  
  232. static void needs_token(token_t tok, char *line, int *offset, int linenum)
  233. {
  234.     token_val_t t;
  235.  
  236.     t = err_get_token(line, offset, linenum);
  237.     if (t.token != tok) {
  238.         fprintf(stderr, "kvik: Unexpected token in line %d:\n", linenum);
  239.         show_err(line, *offset);
  240.         exit(1);
  241.     }
  242. }
  243.  
  244. /** Return 1 if 'tok' is a relational operator.
  245.  **/
  246.  
  247. static int isrelop(token_t tok)
  248. {
  249.     return(tok==T_EQUAL || tok==T_NOT_EQUAL || tok==T_LESS_THAN ||
  250.         tok==T_GREATER_THAN || tok==T_LESS_THAN_OR_EQ ||
  251.         tok==T_GREATER_THAN_OR_EQ);
  252. }
  253.  
  254. /** Return 1 if 'tok' is a valid expression argument.
  255.  **/
  256.  
  257. static int isexprarg(token_t tok)
  258. {
  259.     return(tok==T_REGISTER || tok==T_DATA_POINTER || tok==T_CHANNEL ||
  260.         tok==T_NUMBER || tok==T_CONSTANT);
  261. }
  262.  
  263. /** Return 1 if 'tok' is a valid expression operator.
  264.  **/
  265.  
  266. static int isexprop(token_t tok)
  267. {
  268.     return(isrelop(tok) || tok==T_PLUS || tok==T_MINUS || tok==T_MULTIPLY ||
  269.         tok==T_DIVIDE);
  270. }
  271.  
  272. /** Convert a token into something suitable for passing to the expr function.
  273.  **/
  274.  
  275. static char *expr_arg(token_val_t t)
  276. {
  277.     static char ret[30];
  278.  
  279.     switch (t.token) {
  280.     case T_REGISTER:
  281.         sprintf(ret, "r[%d]", t.val.digit);
  282.         break;
  283.     case T_DATA_POINTER:
  284.         sprintf(ret, "read_data(&d[%d])", t.val.digit);
  285.         break;
  286.     case T_CHANNEL:
  287.         sprintf(ret, "read_channel(%d)", t.val.digit);
  288.         break;
  289.     case T_NUMBER:
  290.         sprintf(ret, "%d", t.val.num);
  291.         break;
  292.     case T_CONSTANT:
  293.         sprintf(ret, "CONST%d", t.val.digit);
  294.     }
  295.  
  296.     return(ret);
  297. }
  298.  
  299. /** Handle assignment statements.
  300.  **/
  301.  
  302. static void assignment(token_val_t tstore, char *line, int *offset, FILE *out,
  303.     int linenum)
  304. {
  305.     token_val_t t;
  306.     int neg = 1;
  307.  
  308.     t = err_get_token(line, offset, linenum);
  309.     if (t.token == T_PROGRAM_POINTER)
  310.         if (tstore.token == T_DATA_POINTER) {
  311.             fprintf(out, "write_data(&d[%d], p[%d]);\n", tstore.val.digit,
  312.                 t.val.digit);
  313.             return;
  314.         }
  315.         else {
  316.             fprintf(stderr, "kvik: Expected program pointer in line %d:\n",
  317.                 linenum);
  318.             show_err(line, *offset);
  319.             exit(1);
  320.         }
  321.  
  322.     switch (tstore.token) {
  323.  
  324.     case T_NUMBER: case T_CONSTANT:
  325.         fprintf(stderr, "kvik: Can't assign to a number/const in line %d:\n",
  326.             linenum);
  327.         show_err(line, 0);
  328.         exit(1);
  329.  
  330.     case T_REGISTER:
  331.         fprintf(out, "r[%d] = ", tstore.val.digit);
  332.         break;
  333.  
  334.     case T_DATA_POINTER:
  335.         fprintf(out, "write_data(&d[%d], ", tstore.val.digit);
  336.         break;
  337.  
  338.     case T_CHANNEL:
  339.         fprintf(out, "write_channel(%d, ", tstore.val.digit);
  340.     }
  341.  
  342.     if (t.token == T_UMINUS) {
  343.         neg = -1;
  344.         t = err_get_token(line, offset, linenum);
  345.     }
  346.  
  347.     if (isexprarg(t.token)) {
  348.         fprintf(out, "expr(%d, %s, ", neg, expr_arg(t));
  349.         t = err_get_token(line, offset, linenum);
  350.         if (isexprop(t.token)) {
  351.             fprintf(out, "%d, ", t.token);
  352.             t = err_get_token(line, offset, linenum);
  353.             if (t.token == T_UMINUS) {
  354.                 neg = -1;
  355.                 t = err_get_token(line, offset, linenum);
  356.             }
  357.             else
  358.                 neg = 1;
  359.             if (isexprarg(t.token))
  360.                 fprintf(out, "%d, %s)", neg, expr_arg(t));
  361.             else {
  362.                 fprintf(stderr, "kvik: Illegal expression in line %d:\n",
  363.                     linenum);
  364.                 show_err(line, *offset);
  365.                 exit(1);
  366.             }
  367.         }
  368.         else if (t.token == T_NEWLINE)
  369.             fprintf(out, "%d, 1, 0)", T_PLUS);
  370.         else {
  371.             fprintf(stderr, "kvik: Expected an operator in line %d:\n",
  372.                 linenum);
  373.             show_err(line, *offset);
  374.             exit(1);
  375.         }
  376.     }
  377.     else {
  378.         fprintf(stderr, "kvik: Illegal expression in line %d:\n", linenum);
  379.         show_err(line, *offset);
  380.         exit(1);
  381.     }
  382.  
  383.     if (tstore.token == T_REGISTER)
  384.         fputs(";\n", out);
  385.     else
  386.         fputs(");\n", out);
  387.  
  388.     return;
  389. }
  390.  
  391.